<?php
/**
 * 微信支付控制器
 * 2015年1月28日17:36:52
 * xiaobei
 */
namespace Mobile\Controller;
use Think\Controller;

class PaywechatController extends Controller
{

    public $parameters; // 静态链接参数
    public $WECHAT_MCHID; // 微信支付商户号
    public $WECHAT_PAYKEY; // 商户支付密钥Key。审核通过后，在微信发送的邮件中查看wxpay_partnerkey
    public $WECHAT_APPID; // 公众号appid
                          
    // =======【证书路径设置】=====================================
    // 证书路径,注意应该填写绝对路径
    public $WXPAY_SSLCERT_PATH;
    public $WXPAY_SSLKEY_PATH;
    
    public function __construct()
    {
        parent::__construct();
        $this->WECHAT_APPID = C('WECHAT_APPID'); // 公号appid
        $this->WECHAT_PAYKEY = C('WECHAT_PAYKEY'); // 支付密匙PartnerKey
        $this->WECHAT_MCHID = C('WECHAT_MCHID'); // 微信支付商户号 PartnerId
        $this->WXPAY_SSLCERT_PATH = C('WXPAY_SSLCERT_PATH'); // 证书路径,注意应该填写绝对路径
        $this->WXPAY_SSLKEY_PATH =  C('WXPAY_SSLKEY_PATH'); // 证书路径,注意应该填写绝对路径

    }
    

    //获取支付参数
    public function getPayCode()
    {

        $prepay_id  = $this->_setPrepayId();
        $jsApiObj["appId"] = $this->WECHAT_APPID;
        $timeStamp = time();
        $jsApiObj["timeStamp"] = (string)"$timeStamp";
        $jsApiObj["nonceStr"] = $this->_create_noncestr();
        $jsApiObj["package"] = "prepay_id={$prepay_id}";
        $jsApiObj["signType"] = "MD5";
        $jsApiObj["paySign"] = $this->_getSign($jsApiObj);

        $js = json_encode($jsApiObj);
        return $js;
    }
    
    /*
     * 关闭订单
     */
    public function closeOrder($out_trade_no)
    {
        $jsApiObj["appid"] = $this->WECHAT_APPID;//公众账号ID
        $jsApiObj["mch_id"] = $this->WECHAT_MCHID;//商户号
        $jsApiObj["out_trade_no"] = $out_trade_no;//订单号
        $jsApiObj["nonce_str"] = $this->_create_noncestr();//随机字符串
        $jsApiObj["sign"] = $this->_getSign($jsApiObj);//签名

        $xml = $this->createXml($jsApiObj);
        $result = $this->_curlPost('https://api.mch.weixin.qq.com/pay/closeorder',$xml);
        // file_put_contents('test2.txt', $result);
        $obj = $this->xmlToArray($result);
        
        //关闭失败
        if($obj['return_code'] != "SUCCESS"){
            //return $obj['return_msg'];
            return false;
        }

        if($obj['result_code'] == "SUCCESS"){
            //关闭成功
            return true;
        }
        
        if($obj['err_code'] == "ORDERNOTEXIST" || $obj['err_code'] == "ORDERCLOSED"){
            //订单不存在 订单已关闭, 当做关闭成功处理
            return true;
        }

        //return $obj['err_code'];
        return false;

    }
    
    
    /*
     * 企业付款
     */
    public function qiyePay($data){
        
        $jsApiObj["mch_appid"] = $this->WECHAT_APPID;//公众账号ID
        $jsApiObj["mchid"] = $this->WECHAT_MCHID;//商户号
        $jsApiObj["partner_trade_no"] = $data['trade_no'];//商户订单号
        $jsApiObj["nonce_str"] = $this->_create_noncestr();//随机字符串
        $jsApiObj["openid"] = $data['openid'];//用户openid
        
        //NO_CHECK：不校验真实姓名 
        //FORCE_CHECK：强校验真实姓名（未实名认证的用户会校验失败，无法转账） 
        //OPTION_CHECK：针对已实名认证的用户才校验真实姓名（未实名认证用户不校验，可以转账成功）
        $jsApiObj["check_name"] = $data['check_name'] ? $data['check_name'] :"NO_CHECK";//用户openid
        
        //如果check_name设置为FORCE_CHECK或OPTION_CHECK，则必填用户真实姓名
        $jsApiObj["re_user_name"] = $data['realname'];
        $jsApiObj["amount"] = $data['amount'];//企业付款金额，单位为分
        $jsApiObj["desc"] = $data['desc'];//企业付款操作说明信息。必填。
        $jsApiObj["spbill_create_ip"] = $data['ip'];//调用接口的机器Ip地址
        
        
        $jsApiObj["sign"] = $this->_getSign($jsApiObj);//签名
        
        $xml = $this->createXml($jsApiObj);
        $result = $this->curl_post_ssl('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers',$xml);
        // file_put_contents('test2.txt', $result);
        $obj = $this->xmlToArray($result);
       // dump($obj);
        if($obj['return_code'] != "SUCCESS"){
            //return $obj['return_msg'];
            //dump($obj['return_msg']);
            return_json(1,$obj['return_msg']);
            return false;
           
        }
        
        if($obj['result_code'] == "SUCCESS"){
            
            //成功
            return true;
        }
        return_json(1,$obj['return_msg']);
        return false;
        
    }
    
    
    /*
     * 发放企业红包
     */
    public function qiyeLuckyMoney($data){
    
        $jsApiObj["mch_billno"] = $data['mch_billno'];//商户订单号（每个订单号必须唯一）组成：mch_id+yyyymmdd+10位一天内不能重复的数字。
        $jsApiObj["nonce_str"] = $this->_create_noncestr();//随机字符串
        $jsApiObj["mchid"] = $this->WECHAT_MCHID;//商户号
        $jsApiObj["wxappid"] = $this->WECHAT_APPID;//微信号
        $jsApiObj["send_name"] = $data['send_name'];//红包发送者
        $jsApiObj["re_openid"] = $data['re_openid'];//用户openid
        $jsApiObj["total_amount"] = $data['total_amount'];//金额,分
        $jsApiObj["total_num"] = 1;//用户openid
        $jsApiObj["wishing"] = $data['wishing'];//	红包祝福语
        $jsApiObj["client_ip"] = $data['ip'];//调用接口的机器Ip地址
        $jsApiObj["act_name"] = $data['act_name'];//活动名称
        $jsApiObj["remark"] = $data['remark'];//备注

        $jsApiObj["sign"] = $this->_getSign($jsApiObj);//签名
    
        $xml = $this->createXml($jsApiObj);
        $result = $this->curl_post_ssl('https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack',$xml);
        // file_put_contents('test2.txt', $result);
        $obj = $this->xmlToArray($result);
    
        //失败
        if($obj['return_code'] != "SUCCESS"){
            //return $obj['return_msg'];
            return false;
        }
    
        if($obj['result_code'] == "SUCCESS"){
            //成功
            return true;
        }
    
        return false;
    
    }
    
    
    /**
     * 设置参数
     */
    public function setParameter($parameter, $parameterValue) {
        $this->parameters[$parameter] = $parameterValue;
    }
    
    /**
     * 	作用：生成签名
     */
    protected function _getSign($Obj)
    {
        foreach ($Obj as $k => $v)
        {
            $Parameters[$k] = $v;
        }
        //签名步骤一：按字典序排序参数
        ksort($Parameters);
        $String = $this->_formatBizQueryParaMap($Parameters, false);
        //echo '【string1】'.$String.'</br>';
        //签名步骤二：在string后加入KEY

        $String = $String."&key=".$this->WECHAT_PAYKEY;
        //echo "【string2】".$String."</br>";
        //签名步骤三：MD5加密

        $String = md5($String);

        //echo "【string3】 ".$String."</br>";
        //签名步骤四：所有字符转为大写
        $result_ = strtoupper($String);
        //echo "【result】 ".$result_."</br>";
        return $result_;
    }
    
    //格式化参数
    protected function _formatBizQueryParaMap($paraMap, $urlencode){
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v){
            if($urlencode){
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar = "";
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }
        return $reqPar;
    }
    
    //生成随机数
    protected function _create_noncestr( $length = 16 ) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {
            $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }
    
    protected function _setPrepayId(){
        $this->parameters["appid"] = $this->WECHAT_APPID;//公众账号ID
        $this->parameters["mch_id"] = $this->WECHAT_MCHID;//商户号
        $this->parameters["nonce_str"] = $this->_create_noncestr();//随机字符串
        $this->parameters["sign"] = $this->_getSign($this->parameters);//签名
        $xml = $this->createXml($this->parameters);
        $result = $this->_curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder',$xml);
       // file_put_contents('test2.txt', $result);
        $obj = $this->xmlToArray($result);
        return $obj['prepay_id'];
    }
    
    /**
     * 	作用：将xml转为array
     */
    public  function xmlToArray($xml)
    {
        //将XML转为array
		$bPreviousValue = libxml_disable_entity_loader(true);
        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
		libxml_disable_entity_loader($bPreviousValue);	
        return $array_data;
    }
    
    public function _curlPost($url,$data){
        $ch = curl_init();
        $header = "Accept-Charset: utf-8";
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $tmpInfo = curl_exec($ch);
        curl_close($ch);
        return $tmpInfo;
    }
    
    /**
     * 生成接口参数xml
     */
    protected function createXml($xml_arr)
    {
        return $this->arrayToXml($xml_arr);
    }
    
    /**
     * 	作用：array转xml
     */
    public function arrayToXml($arr)
    {
        $xml = "<xml>";
        foreach ($arr as $key=>$val)
        {
            if (is_numeric($val))
            {
                $xml.="<".$key.">".$val."</".$key.">";
    
            }
            else
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
        }
        $xml.="</xml>";
        return $xml;
    }
    
    ////////////////////微信支付结束//////////////////////////
    //微信回调
    /*
     * 验证签名
     */
    public function checkSign($xml_arr)
    {
        $tmpData = $xml_arr;
        unset($tmpData['sign']);
        $sign = $this->_getSign($tmpData);//本地签名
        if ($xml_arr['sign'] == $sign) {
            return TRUE;
        }
        return FALSE;
    }
    
    /*
     * 微信支付退款
     */
    //微信退款
    public function getbackParameters($order){
    
        $back['appid'] = $this->WECHAT_APPID;//公众账号ID
        $back['mch_id'] = $this->WECHAT_MCHID;//商户号
        $back['nonce_str'] = $this->_create_noncestr();//随机字符串
        $back['op_user_id'] = $this->WECHAT_MCHID;//商户号
        
        //$back['out_trade_no'] = $order['order_sn'];//内部订单号
        $back['transaction_id'] = $order['transaction_id'];//微信支付订单号
        
        
        $back['out_refund_no'] = $order['order_sn']."_1";//退款单号
        $back['refund_fee'] = intval($order['pay_money']*100);//单位为分
        $back['total_fee'] = intval($order['pay_money']*100);//订单总金额
        
        $back['sign'] = $this->_getSign($back);//签名
        
        return $this->arrayToXml($back);
    
    }
    
    public function curl_post_ssl($url, $vars, $aHeader=array())
    {
        $ch = curl_init();
        //超时时间
        curl_setopt($ch,CURLOPT_TIMEOUT,30);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
    
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
    
        //默认格式为PEM，可以注释
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLCERT,$this->WXPAY_SSLCERT_PATH);
        //默认格式为PEM，可以注释
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLKEY,$this->WXPAY_SSLKEY_PATH);

        if( count($aHeader) >= 1 ){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
        }
    
        curl_setopt($ch,CURLOPT_POST, 1);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$vars);
        $data = curl_exec($ch);
        if($data){
            curl_close($ch);
            return $data;
        }else {
            $error = curl_errno($ch);
            curl_close($ch);
            return  $error;
        }
    }
    
    /*
     * 查询订单订单
     * 当商户后台、网络、服务器等出现异常，商户系统最终未接收到支付通知；
     */
    public function askOrder($out_trade_no)
    {
        $jsApiObj["appid"] = $this->WECHAT_APPID;//公众账号ID
        $jsApiObj["mch_id"] = $this->WECHAT_MCHID;//商户号
        $jsApiObj["out_trade_no"] = $out_trade_no;//订单号
        $jsApiObj["nonce_str"] = $this->_create_noncestr();//随机字符串
        $jsApiObj["sign"] = $this->_getSign($jsApiObj);//签名
    
        $xml = $this->createXml($jsApiObj);
        $result = $this->_curlPost('https://api.mch.weixin.qq.com/pay/orderquery',$xml);
        // file_put_contents('test2.txt', $result);
        $obj = $this->xmlToArray($result);
    
        //失败
        if($obj['return_code'] != "SUCCESS"){
            //return $obj['return_msg'];
            return false;
        }
    
        if($obj['result_code'] == "SUCCESS"){
            //成功
            return $obj;
        }
    
        return false;
    
    }
    
    /*
     * 获取支付的二维码
     * weixin://wxpay/bizpayurl?sign=XXXXX
     * &appid=XXXXX&mch_id=XXXXX
     * &product_id=XXXXXX
     * &time_stamp=XXXXXX&nonce_str=XXXXX
     */
    public function getPayqrcode($out_trade_no){
    
        $jsApiObj["appid"] = $this->WECHAT_APPID;//公众账号ID
        $jsApiObj["mch_id"] = $this->WECHAT_MCHID;//商户号
        $jsApiObj["product_id"] = $out_trade_no;//订单号
        $timeStamp = time();
        $jsApiObj["time_stamp"] = (string)"$timeStamp";
        $jsApiObj["nonce_str"] = $this->_create_noncestr();//随机字符串
        $jsApiObj["sign"] = $this->_getSign($jsApiObj);//签名
    
        $str = http_build_query($jsApiObj);
        $pay_url = "weixin://wxpay/bizpayurl?".$str;
    
        return $pay_url;
    }
    
    
    /*
     * 微信扫码支付回调返回
     */
    public function returnQrcodexml($order)
    {
        ///0待支付,1已付款,,2完成,3.待退款 4已退款,5发货,0未完成,6订单关闭,
    
        if(in_array($order['checked'],array(1,2,3,4,5,6))){
            //已支付
            $qrcodeApiObj['return_code'] = 'FAIL';
            $qrcodeApiObj["result_code"] = 'FAIL';
    
            if(in_array($order['checked'],array(1,2,5))){
                $qrcodeApiObj['return_msg'] = '亲,该订单已支付成功,不能重复支付,请核对订单信息~';
                $qrcodeApiObj["err_code_des"] = "亲,该订单已支付成功,不能重复支付,请核对订单信息~";
            }else if(in_array($order['checked'],array(3,4))){
                $qrcodeApiObj['return_msg'] = '亲,该订单已进入退款流程,无法支付~';
                $qrcodeApiObj["err_code_des"] = '亲,该订单已进入退款流程,无法支付~';
            }else if($order['checked'] == 6){
                $qrcodeApiObj['return_msg'] = '亲,该订单已关闭,不能支付~';
                $qrcodeApiObj["err_code_des"] = "亲,该订单已关闭,不能支付~";
            }
    
    
            $prepay_id  = $this->_setPrepayId();
            $qrcodeApiObj["appid"] = $this->WECHAT_APPID;//公众账号ID
            $qrcodeApiObj["mch_id"] = $this->WECHAT_MCHID;//商户号
            $qrcodeApiObj["nonce_str"] = $this->_create_noncestr();//随机字符串
            $qrcodeApiObj["prepay_id"] = $prepay_id;//与支付id
    
            $qrcodeApiObj["sign"] = $this->_getSign($qrcodeApiObj);
    
        }else if(!empty($order) && $order['checked'] == 0){
    
    
            $qrcodeApiObj['return_code'] = 'SUCCESS';
            $qrcodeApiObj['return_msg'] = 'ok';
    
            $prepay_id  = $this->_setPrepayId();
            $qrcodeApiObj["appid"] = $this->WECHAT_APPID;//公众账号ID
            $qrcodeApiObj["mch_id"] = $this->WECHAT_MCHID;//商户号
            $qrcodeApiObj["nonce_str"] = $this->_create_noncestr();//随机字符串
            $qrcodeApiObj["prepay_id"] = $prepay_id;//与支付id
    
            if($prepay_id){
                $qrcodeApiObj["result_code"] = 'SUCCESS';
            }else{
                $qrcodeApiObj["result_code"] = 'FAIL';
                $qrcodeApiObj["err_code_des"] = "支付失败";
            }
            $qrcodeApiObj["sign"] = $this->_getSign($qrcodeApiObj);
    
        }
    
        $xml = $this->arrayToXml($qrcodeApiObj);
    
        //file_put_contents("ssspay.txt", $xml);
    
        echo $xml;exit;
    }
    
    
    /*
     * 刷卡支付
     */
    public function cardpay($order,$auth_code){
    
        set_time_limit(200);//设置超时时间
    
        $msg = '';
        if(in_array($order['checked'],array(1,2,5))){
    
            $msg = '亲,该订单已支付成功,不能重复支付,请核对订单信息~';
            return_json(1,$msg);
    
        }else if(in_array($order['checked'],array(3,4))){
    
            $msg = '亲,该订单已进入退款流程,无法支付~';
            return_json(1,$msg);
    
        }else if($order['checked'] == 6){
    
            $msg = '亲,该订单已关闭,不能支付~';
            return_json(1,$msg);
    
        }else if(empty($order) || !is_array($order)){
    
            $msg = '亲,系统错误,不能支付~';
            return_json(1,$msg);
    
        }
    
        $carpay["appid"] = $this->WECHAT_APPID;
        $carpay["mch_id"] = $this->WECHAT_MCHID;//商户号
        $carpay["nonce_str"] = $this->_create_noncestr();//随机字符串
        $carpay["body"] = "订单:".$order['order_sn'];//商品或支付单简要描述
    
        $carpay["out_trade_no"] = $order['order_sn'];//商户系统内部的订单号
    
        $carpay["total_fee"] = $order['pay_money']*100;//订单金额
        $carpay["spbill_create_ip"] = $order['order_ip'];//商品或支付单简要描述
        $carpay["auth_code"] = $auth_code;//扫码支付授权码，设备读取用户微信中的条码或者二维码信息
    
        $carpay["sign"] = $this->_getSign($carpay);//签名
    
        $xml = $this->createXml($carpay);
        $result = $this->_curlPost('https://api.mch.weixin.qq.com/pay/micropay',$xml);
    
        $obj = $this->xmlToArray($result);
        //file_put_contents('111.txt', $xml);
        //file_put_contents('111.txt', json_encode($obj));
        //失败
        if($obj['return_code'] != "SUCCESS"){
    
            return false;
        }
    
        if($obj['result_code'] == "SUCCESS"){
            //成功
            //todo
            return $obj;
        }
    
        //支付结果为非成功状态,返回false
        return false;
    
    }
    
    
    /*
     * 扣款失败后查询订单
     */
    public function _check_cardpay($out_trade_no){
    
        $xml_arr = $this->askOrder($out_trade_no);
        $time = 30;
        while(!$xml_arr){
    
            sleep(5);//休息5秒
            $time = $time-5;
            if($time<0){
                break;
            }
            $xml_arr = $this->askOrder($out_trade_no);
    
            if(!empty($xml_arr)){
                $res = $this->checkSign($xml_arr);
                if($res == FALSE){
                    //签名失败
                    $xml_arr = false;
                }
                //判断支付状态
                if($xml_arr['trade_state'] != 'SUCCESS'){
                    //支付失败
                    $xml_arr = false;
                }
    
                if($xml_arr['trade_state'] == 'SUCCESS'){
                    //支付成功
                    //TODO,更改订单状态
                    return $xml_arr;
    
                }
            }
        }
    
        if(!$xml_arr){
            //交易失败,撤销订单
            $res = $this->_reverseOrder($out_trade_no);
            //提示订单已撤销
            return false;
        }
    
        return $xml_arr;
    
    }
    
    
    /*
     * 撤销订单
     */
    protected  function _reverseOrder($out_trade_no){
    
        $jsApiObj["appid"] = $this->WECHAT_APPID;//公众账号ID
        $jsApiObj["mch_id"] = $this->WECHAT_MCHID;//商户号
        $jsApiObj["out_trade_no"] = $out_trade_no;//订单号
        $jsApiObj["nonce_str"] = $this->_create_noncestr();//随机字符串
        $jsApiObj["sign"] = $this->_getSign($jsApiObj);//签名
    
        $xml = $this->createXml($jsApiObj);
        $result = $this->curl_post_ssl('https://api.mch.weixin.qq.com/secapi/pay/reverse',$xml);
    
        $obj = $this->xmlToArray($result);
    
        //失败
        if($obj['return_code'] != "SUCCESS"){
            //return $obj['return_msg'];
            return false;
        }
    
        if($obj['result_code'] == "SUCCESS"){
            //成功
            return $obj;
        }
    
        return false;
    }
    
}
